package org.ljy;

import java.io.*;
import java.nio.Buffer;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ZkLogThreadClassifier {

    private static final String FAVTRIGGER_FLAG = "[FAVTrigger]";
    private static final String INFO_FLAG = " - INFO  ";


    // 提取30m-X中的数字X（用于排序）
    private static Integer extract30mNumber(String folderName) {
        Pattern pattern = Pattern.compile("30m-(\\d+)");
        Matcher matcher = pattern.matcher(folderName);
        if (matcher.matches()) {
            return Integer.parseInt(matcher.group(1));
        }
        return Integer.MAX_VALUE; // 非30m-X格式放最后
    }

    // 提取X_Xf中的第一个数字X（用于排序）
    private static Integer extractSubFolderNumber(String folderName) {
        Pattern pattern = Pattern.compile("(\\d+)_\\d+f");
        Matcher matcher = pattern.matcher(folderName);
        if (matcher.matches()) {
            return Integer.parseInt(matcher.group(1));
        }
        return Integer.MAX_VALUE; // 非X_Xf格式放最后
    }

    public static String extractTargetFromLogLine(String logLine) {
        // 原有提取逻辑不变
        if (logLine.contains(FAVTRIGGER_FLAG)) {
            return null;
        }

        int infoStartIdx = logLine.indexOf(INFO_FLAG);
        if (infoStartIdx == -1) {
            return null;
        }

        int targetLeftBracketIdx = logLine.indexOf('[', infoStartIdx + INFO_FLAG.length());
        if (targetLeftBracketIdx == -1) {
            System.out.printf("⚠️ INFO后无左括号[：%s%n", logLine);
            return null;
        }

        int bracketLevel = 1;
        int targetRightBracketIdx = -1;
        for (int i = targetLeftBracketIdx + 1; i < logLine.length(); i++) {
            char c = logLine.charAt(i);
            if (c == '[') {
                bracketLevel++;
            } else if (c == ']') {
                bracketLevel--;
                if (bracketLevel == 0) {
                    targetRightBracketIdx = i;
                    break;
                }
            }
        }
        if (targetRightBracketIdx == -1) {
            System.out.printf("⚠️ INFO后无匹配的右括号]：%s%n", logLine);
            return null;
        }

        String bracketContent = logLine.substring(targetLeftBracketIdx + 1, targetRightBracketIdx).trim();
        int lastColonIdx = bracketContent.lastIndexOf(':');
        if (lastColonIdx == -1) {
            System.out.printf("⚠️ []内无冒号:：%s → 内容：%s%n", logLine, bracketContent);
            return null;
        }

        int atIdx = bracketContent.indexOf('@');
        if (atIdx == -1 || atIdx <= lastColonIdx) {
            System.out.printf("⚠️ []内无@或@在冒号前：%s → 内容：%s%n", logLine, bracketContent);
            return null;
        }

        return bracketContent.substring(lastColonIdx + 1, atIdx).trim();
    }

    public static List<String> batchExtractFromLogFile(String logFilePath) throws IOException {
        List<String> targetList = new ArrayList<>();
        int totalLines = 0;
        int processedLines = 0;
        int skippedLines = 0;

        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream(logFilePath), StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                totalLines++;
                if (line.contains(FAVTRIGGER_FLAG)) {
                    skippedLines++;
                    continue;
                }
                String target = extractTargetFromLogLine(line);
                if (target != null && !target.isEmpty()) {
                    targetList.add(target);
                    processedLines++;
                }
            }
            System.out.printf("📊 日志处理统计：%n");
            System.out.printf("  - 日志总行数：%d%n", totalLines);
            System.out.printf("  - 跳过FAVTrigger行数：%d%n", skippedLines);
            System.out.printf("  - 有效INFO行数（提取成功）：%d%n", processedLines);
            System.out.printf("  - 最终提取类名数（去重后）：%d%n", new LinkedHashSet<>(targetList).size());
        }

        return new ArrayList<>(new LinkedHashSet<>(targetList));
    }

    public static List<String> processSingleBaseDirectory(String basePath) throws IOException {
        Set<String> allClasses = new LinkedHashSet<>();
        File baseDir = new File(basePath);

        if (!baseDir.exists() || !baseDir.isDirectory()) {
            throw new FileNotFoundException("基础目录不存在: " + basePath);
        }

        System.out.printf("%n================================ 开始处理基础目录: %s ================================%n", basePath);

        // 1. 获取并排序30m-X文件夹（按数字升序）
        File[] testDirs = baseDir.listFiles(File::isDirectory);
        if (testDirs == null) {
            throw new IOException("无法列出基础目录文件: " + basePath);
        }
        List<File> sortedTestDirs = new ArrayList<>(Arrays.asList(testDirs));
        sortedTestDirs.sort(Comparator.comparingInt(dir -> extract30mNumber(dir.getName())));

        for (File testDir : sortedTestDirs) {
            String testDirName = testDir.getName();
            if (!testDirName.startsWith("30m-")) {
                continue;
            }
            System.out.printf("%n===== 开始处理测试文件夹: %s =====%n", testDirName);

            // 2. 获取并排序X_Xf子文件夹（按第一个数字升序）
            File[] subDirs = testDir.listFiles(File::isDirectory);
            if (subDirs == null) {
                System.out.printf("⚠️ 无法列出子目录: %s%n", testDir.getAbsolutePath());
                continue;
            }
            List<File> sortedSubDirs = new ArrayList<>(Arrays.asList(subDirs));
            sortedSubDirs.sort(Comparator.comparingInt(dir -> extractSubFolderNumber(dir.getName())));

            for (File subDir : sortedSubDirs) {
                String subDirName = subDir.getName();
                System.out.printf("%n--- 处理子文件夹: %s ---%n", subDirName);

                File monitorDir = new File(subDir, "monitor");
                if (!monitorDir.exists() || !monitorDir.isDirectory()) {
                    System.out.printf("⚠️ monitor目录不存在: %s%n", monitorDir.getAbsolutePath());
                    continue;
                }

                // 3. 按C1ZK1到C1ZK5顺序处理服务器日志
                for (int i = 1; i <= 5; i++) {
                    String serverDirName = "C1ZK" + i;
                    File serverDir = new File(monitorDir, serverDirName);
                    File logFile = new File(serverDir, "logs/zookeeper--server-" + serverDirName + ".out");

                    if (!logFile.exists() || !logFile.isFile()) {
                        System.out.printf("⚠️ 日志文件不存在: %s%n", logFile.getAbsolutePath());
                        continue;
                    }

                    System.out.printf("正在处理日志文件: %s%n", logFile.getAbsolutePath());
                    List<String> classes = batchExtractFromLogFile(logFile.getAbsolutePath());
                    allClasses.addAll(classes);
                }
            }
        }

        return new ArrayList<>(allClasses);
    }

    // 修改：处理多个基础目录的方法
    public static List<String> processMultipleDirectories(List<String> basePaths) throws IOException {
        Set<String> allUniqueClasses = new LinkedHashSet<>();
        for (String path : basePaths) {
            // 合并当前目录提取的类名（Set自动去重）
            allUniqueClasses.addAll(processSingleBaseDirectory(path));
        }
        return new ArrayList<>(allUniqueClasses);
    }

    private static final String BASE_PATH = "/home/losewinner/crashfuzz/CrashfuzzOutputs/crashfuzz-outputs-0715-48h/bugs/";

    private static final Pattern Bayes_pattern = Pattern.compile("\\[(.*?)\\] 最终先验概率：\\s*(\\d+\\.\\d+)%");
    public static void Bayesfile_Reader(){
        String filePath = "/home/losewinner/crashfuzz_about/bayesian.txt";
        Map<ZkClassCategory.Category, Double> categoryRates = new HashMap<>();
        Map<String,Double> roleRates = new HashMap<>();

        boolean isReadingCate = false;
        boolean isReadingRole = false;

        try(BufferedReader br = new BufferedReader(new FileReader(filePath))){
            String line;
            while((line = br.readLine())!= null){
                line = line.trim();
                if(line.isEmpty()) continue;

                // 切换读取状态：根据文本中的分隔符判断
                if (line.contains("分类最终先验概率")) {
                    isReadingCate= true;
                    isReadingRole = false;
                    continue;
                }
                if (line.contains("角色最终先验概率")) {
                    isReadingRole = true;
                    isReadingCate = false;
                    continue;
                }

                // 匹配正则，提取名称和概率
                Matcher matcher = Bayes_pattern.matcher(line);
                if (matcher.find()) {
                    String name = matcher.group(1).trim(); // 提取[ ]中的名称（如DATA_STORE_AND_SNAPSHOT）
                    double probability = Double.parseDouble(matcher.group(2)); // 提取概率数值（如58.23）

                    // 根据当前状态存入对应Map
                    if (isReadingCate) {
                        ZkClassCategory.Category cate = ZkClassCategory.Category.valueOf(name);
                        categoryRates.put(cate, probability);
                    } else if (isReadingRole) {
                        roleRates.put(name, probability);
                    }
                }
            }

            System.out.println(categoryRates+"\n"+roleRates);

        } catch(IOException e){
            e.printStackTrace();
        } catch(NumberFormatException e){
            e.printStackTrace();
        }
    }

    private static final Pattern Unique_cases_pattern = Pattern.compile("\\*Test (\\d+) unique cases");
    private static final Pattern Bugs_pattern = Pattern.compile("\\*Got (\\d+) bugs\\.");
    public static Double BugToUniqueTest(List<String> outputFilePath){
        List<Integer> uniqueCasesList = new ArrayList<>();
        List<Integer> bugsList = new ArrayList<>();
        for(String path :outputFilePath){
            String filename = path+File.separator+"TEST_REPORT";
            try (BufferedReader br = new BufferedReader(new FileReader(filename))){
                String line;
                while((line = br.readLine())!=null){
                    line = line.trim();
                    Matcher uniqueCasesMatcher = Unique_cases_pattern.matcher(line);
                    if(uniqueCasesMatcher.find()){
                        int number = Integer.parseInt(uniqueCasesMatcher.group(1));
                        uniqueCasesList.add(number);

                    }

                    Matcher bugsMatcher = Bugs_pattern.matcher(line);
                    if(bugsMatcher.find()){
                        int number = Integer.parseInt(bugsMatcher.group(1));
                        bugsList.add(number);
                        break;
                    }
                }
            } catch(IOException e){
                e.printStackTrace();
            }
        }

        int testAllCount = uniqueCasesList.stream().mapToInt(Integer::intValue).sum();
        System.out.println(testAllCount);
        double rate = 0.0;
        for(int i = 0;i<bugsList.size();i++){
            System.out.println("产生bug数量："+bugsList.get(i)+" 独立测试数量: "+uniqueCasesList.get(i));
            rate += ((double)bugsList.get(i)/uniqueCasesList.get(i))*((double)uniqueCasesList.get(i)/testAllCount);
        }

        return rate;
    }

    public static void main(String[] args) throws IOException {
        // 这里可以手动指定多个基础目录，或通过命令行参数传入
        List<String> baseDirectories = new ArrayList<>();
        // 示例：添加多个目录路径（根据实际需求修改）
        baseDirectories.add("/home/losewinner/crashfuzz/CrashfuzzOutputs/crashfuzz-outputs-0715-48h/bugs");
        baseDirectories.add("/home/losewinner/crashfuzz/CrashfuzzOutputs/crashfuzz-outputs-0829-48h/bugs");
        baseDirectories.add("/home/losewinner/crashfuzz/CrashfuzzOutputs/crashfuzz-outputs-0904-72h/bugs");
        baseDirectories.add("/home/losewinner/crashfuzz/CrashfuzzOutputs/crashfuzz-outputs-0908-72h/bugs");
        baseDirectories.add("/home/losewinner/crashfuzz/CrashfuzzOutputs/crashfuzz-outputs-0912-72h/bugs");
/*
        baseDirectories.add("/home/losewinner/crashfuzz/3.8.5zk-outputs/crashfuzz-outputs-11-14-24h-原代码对照组/bugs");
        baseDirectories.add("/home/losewinner/crashfuzz/3.8.5zk-outputs/crashfuzz-outputs-1111-48h/bugs");
        baseDirectories.add("/home/losewinner/crashfuzz/3.8.5zk-outputs/crashfuzz-outputs-1106-5h/bugs");*/
        //double finalrate = BugToUniqueTest(baseDirectories);
        //System.out.println(finalrate);


        // 处理多个目录并获取去重结果
        List<String> allUniqueClasses = processMultipleDirectories(baseDirectories);

        // 按首字母排序（自然排序）
        Collections.sort(allUniqueClasses);

        System.out.printf("%n================================ 所有去重类名结果 ================================%n");
        System.out.printf("共提取到 %d 个唯一类名（已按首字母排序）%n", allUniqueClasses.size());
        for (int i = 0; i < allUniqueClasses.size(); i++) {
            System.out.printf("%d) %s%n", i + 1, allUniqueClasses.get(i));
        }
        System.out.println("=============================================================================");

    }
}